Skip to content

Latest commit

 

History

History
 
 

Section 4 - Information Gathering

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 

Information Gathering

Injecting your code and hooking game functions are two pieces of the puzzle, but the question still remains: how do you know where to install your hook or how to access game data like player positions or health?

Dynamic Analysis

Dynamic analysis involves reading the memory of a running process and/or attaching a debugger to step through its code. It could also involve network packet inspection. Some people even go further and install hooks in important kernel functions (after disabling KPP) to log in real-time every little thing the target does, but I don't have any experience with that.
My preferred tools for dynamic analysis include ReClass.NET, cheat engine, and windbg preview. ReClass is for viewing and mapping out data structures, cheat engine is for searching for specific values in memory, and windbg is for debugging. Cheat engine's debugger is pretty good too and I may often use that when it's available, but windbg will be necessary later when dealing with kernel stuff so it's good to build experience with it.

Static Analysis

Static analysis involves reading the executable file on disk. It could also include looking for log files generated by the target process.
I prefer using HexRays IDA for disassembling and decompiling, but Ghidra is a great (free) alternative that's becoming more and more popular.
If I'm working with any .NET images then I'll use ILSpy with the reflexIL plugin for making changes (if possible). Most .NET disassemblers have decompilers built-in, too, if you're working with a .NET image instead of a native image. IDA and Ghidra also have .NET decompilers, I think, but I prefer ILSpy so I don't have much experience with them.

The value of having a decompiler (not just a disassembler) cannot be understated. IDA and Ghidra both have great decompilers capable of turning boring, meticulous assembly into pseudo-C code. Not only does this take away the eyesore of assembly, but it also makes the logic easier to understand. Trying to figure out what a function does by looking at it in assembly form might take half an hour, but running it through the decompiler and reading it in pseudo-C form might reduce that down to just 5 minutes. It's truly a game changer.

Open Source

Many game engines are completely open source. Many games also use open source packages, too, like networking libraries, input libraries, or scripting engines. If you can identify what the game is built with then you can look to see if it's open source. With the source code in hand, information gathering becomes so much easier. Keep in mind there may be changes between the published source code and the code used in whatever game you're looking at. Usually these are small changes, like a struct having an additional 4-byte field somewhere, or a function might be compiled to different assembly instructions but still ultimately does the same thing in mostly the same way.
Also, keep in mind that even if a game engine isn't open source but is still free to use then it might be worth downloading it and building a simple game to see if it'll provide you with symbols for debugging. Loading symbols into your preferred disassembler is almost just as good as having the source code. To be clear, you'd load your simple game into the disassembler and load the *.pdb. The goal is to figure out how the engine works which you can then apply this knowledge to the actual target game.

All Together Now

Dynamic analysis, static analysis, and source code can all be used together at the same time to make information gathering extremely efficient.
I'll often use a dynamic analysis tool to scan for my player character's health or position and once I find it and figure out what writes to it then I'll translate the address of that function to its filetime address and look at it in my static analysis tool. If the game is using an open source engine then I'll look for nearby strings and search for those strings in the source code, too. Very quickly I'll have an understanding of exactly what's happening, what the call chain looks like, all the structures referenced throughout the chain, etc.
This is just an example but you can see how using all these tools together can make your life easier.
Before moving on, I also want to note that even without source code it's not a bad idea to look at all the referenced strings in the image with your static analysis tool. Often times debug strings will lead you to very juicy functions that reference all kinds of structures you might be interested in.

Other Useful Tools

For unity games built upon the il2cpp backend, il2cppinspector by djkaty is a great tool. It can generate a fully functional DLL project with all of the game's (and engine's) structs and functions defined.
For flash / adobe AIR games I recommend ffdec. It includes a pretty good decompiler and also lets you view and modify the actionscript bytecode.
For Java games I've used recaf, jd-gui, and jbe. They all accomplish the same goal, but I've found some have trouble with certain versions of java. Recaf is probably the most updated one followed by jd-gui.
For dumping games in memory (useful if the game is packed on disk) I use Scylla, but any dumper should do.
For viewing process properties (like checking its protection status and security tokens) I use processhacker. I've used this mostly to verify that my injector process gets the highest level of protection (PsProtectedSignerWinTcb) before I try to get a handle to a certain protected game.

Summary And A Tip

Hopefully this section gave you some ideas of how you can hunt down the information you're looking for.
As a tip (and a recommendation), I strongly urge you to consider writing a program that defines several different structs of varying complexity: one struct with just plain data members, another struct with plain data members and pointers (that are actually pointing to something!), a third struct with strings and integer arrays, a fourth struct with virtual member functions, and a fifth struct with inheritance. Instantiate instances of these structs and print their addresses. Then, point ReClass.NET at these addresses and learn. This is by far the best thing you can do when starting out.

From this point on, the guide will be focused more on practical topics instead of theoretical topics, and I'll try my best to adjust my writing to reflect that with more thoroughness and directness.